﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SHomeWorkshop.LunarConcept.ModifingManager;
using System.Windows;
using System.Xml;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.Controls;
using SHomeWorkshop.LunarConcept.Widgets;
using SHomeWorkshop.LunarConcept.Widgets.Interfaces;

namespace SHomeWorkshop.LunarConcept.Commands.TextCommands
{
    /// <summary>
    /// 创建时间：2012年2月17日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：提供自定义字符串命令的执行方法。
    ///           条件：⑴类名必须以“_TC”开头，否则会无法调用。
    ///                   类名即内置命令文本，用户输入的命令文本将被转换（通过映射表）成内置命令，
    ///                   根据内置命令字符串（即类名），找到类，并调用必须实现的下列方法：
    ///                 ⑵类必须实现带一个string型参数的:
    ///                   static string Execute(string parameters)方法，
    ///                   此方法必须自行处理parameters中以半角空格分隔的命令参数列表（当然，如果不需要，也可不处理）。
    /// </summary>
    [Tools.TextCommandAttribute("/zh/bjzh/fs/fontsize/字号/部件字号/", Enums.TextCommandType.Appearance, "强行设置选定部件字号")]
    public class _TCSetWidgetsFontSize
    {
        /// <summary>
        /// [静态方法]
        /// </summary>
        /// <param name="parameters">字符串形式的参数列表（参数间用半角空格分隔）。</param>
        /// <returns>顺利执行返回string.Empty，否则返回错误信息字符串。</returns>
        public static string Execute(string parameters)
        {
            if (parameters != null && parameters.Trim() == "?")
            {
                TextCommandHelp.ShowHelp("_TCSetWidgetsFontSize");
                return string.Empty;
            }

            if (Globals.MainWindow == null) return "　　未找到主窗口。";

            LunarConcept.Controls.EditorManager manager = Globals.MainWindow.EditorManager;
            if (manager == null) return "　　未找到主窗口的页面管理器。";

            try
            {
                double newFontSize = double.Parse(parameters.Trim());
                if (newFontSize < 10 || newFontSize > 96) return "　　字号必须在[10，96]区间之中。";

                List<Widgets.Widget> selectedWidgets = manager.GetSelectedWidgetsList();

                if (selectedWidgets.Count <= 0) return "　　未选定部件。";

                int titleCount = 0;
                {
                    foreach (Widget w in selectedWidgets)
                    {
                        if (w.TitleLevel != Enums.TitleStyle.Normal) titleCount++;
                    }
                }

                if (titleCount > 0)
                {
                    MessageBox.Show(string.Format("　　选定的 {0} 个部件中，有 {1} 个是标题，此功能只对非标题部件有效！", selectedWidgets.Count, titleCount),
                        Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                }

                ModifingInfo info = new ModifingInfo() { ModifingDescription = "设置选定部件的字号" };
                manager.GetSelectedPageEditorStatus(info);
                manager.GetSelectedWidgetStatus_Old(info);
                manager.GetSelectedWidgetStatus_New(info);

                ModifingItem<Action, ModifingInfo> mi = new ModifingItem<Action, ModifingInfo>(info);

                XmlDocument tmpDoc = new XmlDocument();

                //被挂接的线（不一定会有成员）。
                List<ILinkableLine> linkedLines = new List<ILinkableLine>();

                foreach (Widgets.Widget w in selectedWidgets)
                {
                    if (w.TitleLevel != Enums.TitleStyle.Normal) continue;

                    //对于实现了ICanBeLinkedWidget接口的各部件来说，
                    //只有ContentWidget字型、字号、加粗、倾斜等发生改变时才需要保持中心点。
                    //矩形、菱形、椭圆不会因文本变化而改变部件体积。
                    ContentWidget cw = w as ContentWidget;
                    if (cw == null)
                    {
                        ReplaceAttribute(newFontSize, mi, w);
                    }
                    else
                    {
                        if (cw.IsLinked)
                        {
                            #region 取出所有挂接的线（不管被挂接的线是否两个端点均挂接都算）

                            foreach (UIElement uePage in manager.Children)
                            {
                                PageEditor pe = uePage as PageEditor;
                                if (pe == null) continue;

                                foreach (UIElement ue in pe.Children)
                                {
                                    ILinkableLine linkedLine = ue as ILinkableLine;
                                    if (linkedLine == null) continue;

                                    if (linkedLine.StartMasterId == w.Id || linkedLine.EndMasterId == w.Id)
                                    {
                                        if (linkedLines.Contains(linkedLine) == false)
                                        {
                                            linkedLines.Add(linkedLine);
                                        }
                                    }
                                }
                            }

                            #endregion

                            Point oldTopLeft = cw.TopLeft;
                            Point oldBottomRight = cw.BottomRight;//备用

                            ReplaceAttribute(newFontSize, mi, w);

                            //保持中心点
                            Point oldCenter = new Point(oldTopLeft.X + (oldBottomRight.X - oldTopLeft.X) / 2,
                                oldTopLeft.Y + (oldBottomRight.Y - oldTopLeft.Y) / 2);
                            cw.InvalidateArrange(); cw.UpdateLayout();

                            Point newTopLeft = cw.TopLeft;
                            Point newBottomRight = cw.BottomRight;
                            Point newLocation = new Point(oldCenter.X - (newBottomRight.X - newTopLeft.X) / 2,
                                oldCenter.Y - (newBottomRight.Y - newTopLeft.Y) / 2);

                            Action actNewLocation = new Action(cw.MasterEditor.Id, cw.Id, cw.GetType().Name, XmlTags.LocationTag,
                                cw.Location.ToString(), newLocation.ToString());
                            cw.Location = newLocation;
                            mi.AddAction(actNewLocation);
                        }
                        else
                        {
                            ReplaceAttribute(newFontSize, mi, w);
                        }
                    }
                }

                #region
                if (linkedLines.Count > 0)
                {
                    foreach (ILinkableLine linkedLine in linkedLines)
                    {
                        Widget startMaster = linkedLine.MasterEditor.GetWidget(linkedLine.StartMasterId);
                        Widget endMaster = linkedLine.MasterEditor.GetWidget(linkedLine.EndMasterId);
                        if (startMaster == null || endMaster == null) continue;//如果有一个已经被删除，则不进行位移。

                        Rect rectStart = new Rect(startMaster.TopLeft, startMaster.BottomRight);
                        rectStart.X -= 4; rectStart.Y -= 4; rectStart.Width += 8; rectStart.Height += 8;
                        Rect rectEnd = new Rect(endMaster.TopLeft, endMaster.BottomRight);
                        rectEnd.X -= 4; rectEnd.Y -= 4; rectEnd.Width += 8; rectEnd.Height += 8;

                        Point startCenter = new Point(rectStart.Left + (rectStart.Width / 2), rectStart.Top + (rectStart.Height / 2));
                        Point endCenter = new Point(rectEnd.Left + (rectEnd.Width / 2), rectEnd.Top + (rectEnd.Height / 2));

                        PointToRect.ArrowPoints aptStart = PointToRect.GetCrossPointToRect(rectStart, endCenter);
                        PointToRect.ArrowPoints aptEnd = PointToRect.GetCrossPointToRect(rectEnd, startCenter);

                        Action actStart = new Action(linkedLine.MasterEditor.Id, linkedLine.Id, linkedLine.GetType().Name, XmlTags.StartPointTag,
                            linkedLine.StartPoint.ToString(), aptStart.Top.ToString());
                        linkedLine.StartPoint = aptStart.Top;

                        Action actEnd = new Action(linkedLine.MasterEditor.Id, linkedLine.Id, linkedLine.GetType().Name, XmlTags.EndPointTag,
                            linkedLine.EndPoint.ToString(), aptEnd.Top.ToString());
                        linkedLine.EndPoint = aptEnd.Top;

                        mi.AddAction(actStart);
                        mi.AddAction(actEnd);
                    }
                }
                #endregion

                manager.RegisterModifingItem(mi);

                return string.Empty;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        /// <summary>
        /// 替换Xml文本中FontSize特性(Attribute)。
        /// </summary>
        /// <param name="newFontSize">[可空参数]如果newFontSize的值为null。则去除可能存在的Xml FontSize Attribute</param>
        /// <param name="mi"></param>
        /// <param name="w"></param>
        /// <param name="removeBaseLineAttribute">是否同时去除可能存在的上下标Xml特性。默认不去除。</param>
        public static void ReplaceAttribute(double? newFontSize,
            ModifingItem<Action, ModifingInfo> mi, Widgets.Widget w, bool removeBaseLineAttribute = false)
        {
            XmlNode paragraphSetNode = w.ParagraphSetNode;
            string oldXml = paragraphSetNode.InnerXml;

            //<ParagraphSet <Paragraph <Text 

            XmlNodeList paragraphNodes = paragraphSetNode.SelectNodes(XmlTags.ParagraphTag);

            if (newFontSize != null && newFontSize.HasValue)
            {
                foreach (XmlNode paragraphNode in paragraphNodes)
                {
                    XmlNodeList textNodes = paragraphNode.SelectNodes(XmlTags.TextTag);
                    foreach (XmlNode textNode in textNodes)
                    {
                        textNode.SetAttribute(XmlTags.FontSizeTag, newFontSize.Value.ToString());
                    }
                }
            }
            else
            {
                //去除可能存在的XmlAttribute
                if (removeBaseLineAttribute)
                {
                    foreach (XmlNode paragraphNode in paragraphNodes)
                    {
                        XmlNodeList textNodes = paragraphNode.SelectNodes(XmlTags.TextTag);
                        foreach (XmlNode textNode in textNodes)
                        {
                            XmlAttribute attrFoneSize = textNode.GetAttribute(XmlTags.FontSizeTag);
                            if (attrFoneSize != null)
                            {
                                textNode.RemoveAttributeByName(XmlTags.FontSizeTag);
                            }

                            XmlAttribute attrBaseLineAlignment = textNode.GetAttribute(XmlTags.BaseLineAlignmentTag);
                            if (attrBaseLineAlignment != null)
                            {
                                textNode.RemoveAttributeByName(XmlTags.BaseLineAlignmentTag);
                            }
                        }
                    }
                }
                else
                {
                    foreach (XmlNode paragraphNode in paragraphNodes)
                    {
                        XmlNodeList textNodes = paragraphNode.SelectNodes(XmlTags.TextTag);
                        foreach (XmlNode textNode in textNodes)
                        {
                            XmlAttribute attrFoneSize = textNode.GetAttribute(XmlTags.FontSizeTag);
                            if (attrFoneSize != null)
                            {
                                textNode.RemoveAttributeByName(XmlTags.FontSizeTag);
                            }
                        }
                    }
                }
            }

            Action act = new Action(w.MasterEditor.Id, w.Id, w.GetType().Name, XmlTags.XmlDataInnerXml,
                oldXml, paragraphSetNode.InnerXml);
            w.Build();//已更改，直接调用。
            mi.AddAction(act);
        }
    }
}
